package com.zjt.smart.mvp.presenter.base;

import android.text.TextUtils;

import com.google.gson.JsonElement;
import com.google.gson.JsonSyntaxException;
import com.zjt.smart.api.server.BaseServer;
import com.zjt.smart.mvp.view.LoadView;
import com.zjt.smart.util.Json;

import java.util.List;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;

public abstract class DefaultCallback<DataType> extends BaseCallback {

    private static final String TAG = "DefaultCallback";
    protected LoadView<DataType> mLoadView;
    protected BaseServer mServer;
    protected Call<DataType> mCall;

    public DefaultCallback(Call call, LoadView<DataType> loadView, BaseServer server) {
        mCall = call;
        mLoadView = loadView;
        mServer = server;
    }

    @Override
    public void onLoadCache(long cacheTime, String cacheStr) {
        if (mCall == null || mCall.isCanceled()){
            return;
        }
        if (TextUtils.isEmpty(cacheStr)) {
            mLoadView.onCache(0, null);
            return;
        }
        BaseServer.ResponseHolder holder = null;
        try {
            holder = (BaseServer.ResponseHolder) Json.fromJson(cacheStr, mServer.getHolderClass());
        } catch (Exception e) {
            mLoadView.onCache(cacheTime, null);
            return;
        }
        if (holder == null) {
            mLoadView.onCache(cacheTime, null);
            return;
        }
        if (holder.getCode() != mServer.getOkCode()) {
            mLoadView.onCache(cacheTime, null);
            return;
        }
        JsonElement result = holder.getResult();
        if (result == null || result.isJsonArray() && result.getAsJsonArray().size() == 0
                || result.isJsonNull() || TextUtils.isEmpty(result.toString())) {
            mLoadView.onCache(cacheTime, null);
            return;
        }
        List<DataType> list = parseResult(holder.getResult().toString());
        mLoadView.onCache(cacheTime, list);

    }

    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        if (mCall.isCanceled()){
            return;
        }
        if (!response.isSuccess()) {
            mLoadView.onFail(response.code(), "At " + TAG + "#onResponse-> " + response.errorBody().toString());
            return;
        }

        String jsonStr = "";
        try {
            jsonStr = response.body().string();
            BaseServer.ResponseHolder holder = (BaseServer.ResponseHolder) Json.fromJson(jsonStr, mServer.getHolderClass());
            if (holder.getCode() != mServer.getOkCode()) {
                mLoadView.onFail(holder.getCode(), holder.getMsg());
                return;
            }
            JsonElement result = holder.getResult();
            if (result == null || result.isJsonArray() && result.getAsJsonArray().size() == 0
                    || result.isJsonNull() || TextUtils.isEmpty(result.toString())) {
                mLoadView.onFail(mServer.NO_MORE, "At " + TAG + "#onResponse-> No More");
                return;
            }
            List<DataType> list = parseResult(holder.getResult().toString());
            if (list == null || list.size() == 0){
                mLoadView.onFail(mServer.NO_MORE, "At " + TAG + "#onResponse-> No More");
                return;
            }
            mLoadView.onSuccess(list);

        } catch (JsonSyntaxException e) {
            e.printStackTrace();
            mLoadView.onFail(mServer.PARSE, "At " + TAG + "#onResponse-> Parse Error:"+jsonStr);
        } catch (Exception e) {
            e.printStackTrace();
            // Can't Find Object.
            if(response.code() == mServer.NO_CONTENT) {
                mLoadView.onFail(mServer.NO_CONTENT, "At " + TAG + "#onResponse-> No Content");
            } else {
                mLoadView.onFail(mServer.SYNTAX, "At " + TAG + "#onResponse-> Can't Find Object.Because JSONNull");
            }
        }
    }

    protected abstract List<DataType> parseResult(String result);

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        if (mCall == null || mCall.isCanceled()){
            return;
        }
        mLoadView.onFail(mServer.PARSE, "At " + TAG + "#onFailure-> " + t.toString());
    }
}
